package auth

import (
	"bytes"
	"crypto/md5"
	"encoding/json"
	"fmt"
	"go.getaway.adminspro.padmins.com/untils"
	"go.getaway.adminspro.padmins.com/untils/handler"
	"math/rand"
	"net/http"
	"time"
)

func Login(c *handler.Handler) (map[string]interface{}, untils.Error) {
	params := map[string]string{
		"account":  c.Request.Params("account", "").(string),
		"password": c.Request.Params("password", "").(string),
	}

	if params["account"] == "" {
		return nil, untils.BusinessErrorf("账号不能为空")
	}

	if params["password"] == "" {
		return nil, untils.BusinessErrorf("密码不能为空")
	}

	Db := c.Db
	row, _ := Db.Find("select * from admin where email=? or username=?", params["account"], params["account"])

	if row == nil {
		return nil, untils.BusinessErrorf("账号或密码无效")
	}

	loc, _ := time.LoadLocation("Local")
	updateTime, _ := time.ParseInLocation(untils.DateLayout("Y-m-d H:i:s"), row["update_time"].(string), loc)

	if row["loginfailure"].(int64) >= 10 && updateTime.Unix() >= time.Now().Unix()-300 {
		return nil, untils.BusinessErrorf("密码输入错误次数超过%v次，请5分钟后再尝试！", row["loginfailure"])
	}

	if row["password"].(string) != fmt.Sprintf("%x", md5.Sum([]byte(fmt.Sprintf("%x", md5.Sum([]byte(params["password"])))+row["salt"].(string)))) {
		row["update_time"] = untils.Date("Y-m-d H:i:s")
		row["loginfailure"] = row["loginfailure"].(int64) + 1

		Result, e := Db.Execute("update admin set loginfailure=?,update_time=? where id=?", row["loginfailure"], row["update_time"], row["id"])

		if e != nil {
			return nil, untils.BusinessErrorf("登录失败")
		}

		RowsAffected, e := Result.RowsAffected()

		if e != nil || RowsAffected <= 0 {
			return nil, untils.BusinessErrorf("登录失败")
		}

		loginfailure := 10 - row["loginfailure"].(int64)

		if loginfailure <= 0 {
			return nil, untils.BusinessErrorf("账号或密码无效，错误次数超过10次，请5分钟后再尝试！")
		}

		if loginfailure <= 3 {
			return nil, untils.BusinessErrorf("账号或密码无效，错误次数剩余%d次", loginfailure)
		}

		return nil, untils.BusinessErrorf("账号或密码无效")
	}

	if row["status"].(int64) == 0 {
		return nil, untils.BusinessErrorf("账号已禁用")
	}

	row["login_time"] = untils.Date("Y-m-d H:i:s")
	row["update_time"] = untils.Date("Y-m-d H:i:s")
	row["loginfailure"] = 0
	rand.Seed(time.Now().UnixNano())
	row["token"] = fmt.Sprintf("%x", md5.Sum([]byte(row["login_time"].(string)+string(rand.Intn(99999-10000)+10000))))
	Result, e := Db.Execute(
		"update admin set login_time=?,token=?,token_expiry_time=?,update_time=?,loginfailure=? where id=?",
		row["login_time"],
		row["token"],
		row["token_expiry_time"],
		row["update_time"],
		row["loginfailure"],
		row["id"],
	)
	if e != nil {
		return nil, untils.BusinessErrorf("登录失败")
	}

	RowsAffected, e := Result.RowsAffected()

	if e != nil || RowsAffected <= 0 {
		return nil, untils.BusinessErrorf("登录失败")
	}

	data := make(map[string]interface{})
	data["admin"] = map[string]string{
		"token": fmt.Sprintf("%d-%s", row["id"].(int64), row["token"].(string)),
	}

	Cookie := &http.Cookie{
		Name:     "token",
		Value:    fmt.Sprintf("%d-%s", row["id"].(int64), row["token"].(string)),
		MaxAge:   0,
		Domain:   "",
		Path:     "/",
		Secure:   false,
		HttpOnly: false,
	}

	c.Response.HeaderAdd("Set-Cookie", Cookie.String())

	e = log(c, row)
	if e != nil {
		return nil, untils.BusinessErrorf(e.Error())
	}
	return data, nil
}

func log(c *handler.Handler, row map[string]interface{}) error {
	if c.Request.Method() == "POST" {
		content := bytes.NewBuffer([]byte{})
		jsonEncoder := json.NewEncoder(content)
		jsonEncoder.SetEscapeHTML(false)
		params := c.Request.Params().(map[string]interface{})
		if _, ok := params["password"]; ok {
			params["password"] = "******"
		}
		_ = jsonEncoder.Encode(params)
		e := c.Auth.Log(map[string]interface{}{
			"admin_id":    row["id"],
			"username":    row["username"],
			"url":         untils.MbSubStr(c.Request.Header("Referer"), 0, 255),
			"title":       "登录",
			"content":     content.String(),
			"ip":          c.Request.Ip(),
			"useragent":   untils.MbSubStr(c.Request.Header("User-Agent"), 0, 1000),
			"create_time": untils.Date("Y-m-d H:i:s"),
		})

		if e != nil {
			return e
		}
	}

	return nil
}

func Logout(c *handler.Handler) (map[string]interface{}, untils.Error) {
	Cookie := &http.Cookie{
		Name:     "token",
		Value:    "",
		MaxAge:   0,
		Domain:   "",
		Path:     "/",
		Secure:   false,
		HttpOnly: false,
	}

	c.Response.HeaderAdd("Set-Cookie", Cookie.String())
	return map[string]interface{}{}, nil
}

func GetPicCaptchaConfig(c *handler.Handler) (map[string]interface{}, untils.Error) {
	data := map[string]interface{}{
		"picCaptcha": false,
	}
	return data, nil
}

func GetInfo(c *handler.Handler) (map[string]interface{}, untils.Error) {
	rules := c.Auth.GetResource(c.Auth.Get("id"))
	data := map[string]interface{}{
		"auth":  c.Auth.GetData(),
		"rules": rules,
	}
	return data, nil
}
